package com.zrfintech.common.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;

/**
 * 生成签名
 *
 * @author tangyuanliang
 */
public class SignUtil {
    /**
     * 日志.
     */
    private static Logger LOGGER = LoggerFactory.getLogger(SignUtil.class);

    private static final String encoding = "UTF-8";

    private static final String joinKey = "&";

    private static final String MODEL_1 = "1";

    private static final String MODEL_0 = "0";

    private static final String LOGIN_SK = "login";

    /**
     * 生成登陆秘钥
     */
    public static String generatelLoginSk(String userId) {
        try {
            String md5Str = userId + joinKey + LOGIN_SK;
            LOGGER.info("[generatelLoginKey]md5Hex string={}", md5Str);
            return DigestUtils.md5Hex(md5Str);
        } catch (Exception e) {
            LOGGER.error("[generatelLoginKey]exception.", e);
        }
        return "";
    }

    /**
     * sign签名加密-MD5
     */
    public static String generateSignValue(String sk, String requestId, String time) {
        try {
            String md5Str = sk + joinKey + requestId + joinKey + time;
            LOGGER.info("[generateSignValue]md5Hex string={}", md5Str);
            return DigestUtils.md5Hex(md5Str);
        } catch (Exception e) {
            LOGGER.error("[generateSignValue]exception.", e);
        }
        return "";
    }
    
    /**
     * sign签名加密-SHA256
     */
    public static String generateSHA256Sign(String sk, String requestId, String time) {
        try {
            String sha256Str = sk + joinKey + requestId + joinKey + time;
            LOGGER.info("[generateSHA256Sign]sha256Hex string={}", sha256Str);
            return DigestUtils.sha256Hex(sha256Str);
        } catch (Exception e) {
            LOGGER.error("[generateSHA256Sign]exception.", e);
        }
        return "";
    }

    public static String genSignValue(Map<String, String> params, String token) {
        Map<String, Object> paramMap = new TreeMap<String, Object>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        paramMap.putAll(params);

        StringBuffer buffer = new StringBuffer();
        for (Entry<String, Object> entry : paramMap.entrySet()) {
            buffer.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }

        buffer.append(DigestUtils.md5Hex(token));
        String signValue = DigestUtils.md5Hex(buffer.substring(1));

        return signValue;
    }

    /**
     * 高德地图API sign签名加密
     */
    public static String generateSignValue(Map<String, String> params, String sk) {
        return generateSignValue(null, params, sk);
    }

    /**
     * 百度地图API、腾讯地图API sign签名加密
     */
    public static String generateSignValue(String getUrl, Map<String, String> params, String sk) {
        try {
            String paramsStr = null;
            if (StringUtils.isBlank(getUrl)) {
                paramsStr = toQueryStringByGD(params, sk);
            } else {
                paramsStr = toQueryString(getUrl, params, sk);
            }

            // 整体再次utf8编码
            String tempStr = URLEncoder.encode(paramsStr, encoding);

            return DigestUtils.md5Hex(tempStr);
        } catch (Exception e) {
            LOGGER.error("[lbsAddressService-generateSignValue]exception.", e);
        }
        return null;
    }

    /**
     * 腾讯地图API sign签名加密
     */
    public static String generateSignValueByTx(String getUrl, Map<String, String> params, String sk) {
        try {
            String paramsStr = toQueryStringByTx(getUrl, params, sk);
            return DigestUtils.md5Hex(paramsStr);
        } catch (Exception e) {
            LOGGER.error("[lbsAddressService-generateSignValue]exception.", e);
        }
        return null;
    }

    /**
     * 生成签名
     *
     * @return 签名
     */
    public static String makeSign(String key, Map<String, String> map) {
        List<Entry<String, Object>> list = new ArrayList(map.entrySet());
        list.sort(Comparator.comparing(Entry::getKey));
        String var1 = toUrlParams(list) + "&key=" + key;
        return DigestUtils.md5Hex(var1);
    }

    /**
     * 转为URL参数格式
     *
     * @return 结果
     */
    private static String toUrlParams(List<Entry<String, Object>> list) {
        StringBuilder sb = new StringBuilder();
        for (Entry<String, Object> map : list) {
            String val = String.valueOf(map.getValue());
            if (!"sign".equals(map.getKey()) && !StringUtils.isEmpty(val)) {
                sb.append(map.getKey()).append("=").append(map.getValue()).append("&");
            }
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


    // 对Map内所有value作utf8编码，并拼接返回结果
    private static String toQueryString(String getUrl, Map<?, ?> params, String sk)
            throws UnsupportedEncodingException {
        StringBuffer buffer = new StringBuffer(getUrl);
        for (Entry<?, ?> pair : params.entrySet()) {
            buffer.append(pair.getKey() + "=");
            buffer.append(URLEncoder.encode((String) pair.getValue(), encoding) + "&");
        }
        if (buffer.length() > 0) {
            buffer.deleteCharAt(buffer.length() - 1);
        }
        buffer.append(sk);

        return buffer.toString();
    }

    // 对Map内所有value作utf8编码，并拼接返回结果 高德地图
    private static String toQueryStringByGD(Map<?, ?> params, String sk) throws UnsupportedEncodingException {
        StringBuffer buffer = new StringBuffer();
        for (Entry<?, ?> pair : params.entrySet()) {
            buffer.append(pair.getKey() + "=");
            buffer.append(URLEncoder.encode((String) pair.getValue(), encoding) + "&");
        }
        if (buffer.length() > 0) {
            buffer.deleteCharAt(buffer.length() - 1);
        }
        buffer.append(sk);

        return buffer.toString();
    }

    /**
     * 对Map内所有value 按key升序排列 并拼接返回结果 腾讯地图
     *
     * @param getUrl
     * @param params
     * @param sk
     * @return
     * @throws UnsupportedEncodingException
     */
    private static String toQueryStringByTx(String getUrl, Map<String, String> params, String sk) {
        StringBuffer buffer = new StringBuffer(getUrl);
        for (Entry<String, String> pair : params.entrySet()) {
            buffer.append(pair.getKey() + "=");
            buffer.append(pair.getValue() + "&");
        }
        if (buffer.length() > 0) {
            buffer.deleteCharAt(buffer.length() - 1);
        }
        buffer.append(sk);

        return buffer.toString();
    }

    /**
     * 生成唯一RequestId，毫秒时间戳 + 8位UUID
     *
     * @return
     */
    public static String generateRequestId() {
        String uuid = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "").substring(0, 16);
        String mrmVersion = DateUtil.format(new Date(), DateUtil.LLONG_FORMAT) + "-" + uuid;
        return mrmVersion;
    }

    /**
     * 模型分查询码
     */
    public static String generateModelCode(List<Integer> modelIndex) {
        if (CollectionUtils.isEmpty(modelIndex)) {
            return null;
        }
        StringBuffer modelCode = new StringBuffer();
        Collections.sort(modelIndex, Collections.reverseOrder());
        Integer max = modelIndex.get(0);
        if (max < modelIndex.size()) {
            return null;
        }
        for (int i = 1; i <= max; i++) {
            if (modelIndex.contains(i)) {
                modelCode.append(MODEL_1);
            } else {
                modelCode.append(MODEL_0);
            }
        }
        return modelCode.toString();
    }

    public static String getSignOriginal(Map<String, Object> jsonMap) {
        List<Entry<String, Object>> list = new ArrayList(jsonMap.entrySet());
        //升序排序
        Collections.sort(list, Comparator.comparing(Entry::getKey));

        StringBuilder sb = new StringBuilder();
        for (Entry entry : list) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        if (sb.length() > 1) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("b", 11);
        map.put("e", 11);
        map.put("u", 11);
        map.put("p", 11);
        map.put("a", 11);
        map.put("c", 11);
        String mm = getSignOriginal(map);
        System.out.println(mm);
    }
}
